
/*
 * Controller.m: the controlling object of the Smart Installer application.
 *
 * Copyright (C) 1994, Yves Arrouye <Yves.Arrouye@imag.fr>
 *
 */
 
/*
 * The Smart Installer application and the Smart Package utility suite may be
 * copied and distributed freely, as long as an acknowledgement of the author's
 * work, with its name and address, is kept. The code may not be distributed if
 * it has been modified. Modified code propositions should be directed to the
 * author who will made them if necessary and redistribute the packages.
 *
 */

#import <string.h>

#import <sys/types.h>
#import <sys/dir.h>

#import "Controller.h"
#import "SmartInstaller.h"

@implementation Controller

enum exit_codes {
    EXIT_OK,			// No error
    
    EXIT_USAGE,			// Bad usage
    
    EXIT_NO_ROOT,		// Not located on the root of the filesystem
    EXIT_NO_PACKAGE,		// Cannot find a package
    EXIT_NO_UNICITY,		// Multiple packages on disk
    EXIT_NO_INSTALL,		// The user does not want to deo the install
    EXIT_NO_FORK,		// Cannot fork
    EXIT_NO_SHELL		// Cannot run in a shell
};


- installPackageAndExit:sender
{
    exit([installer installPackage]);
    
    return self;	// Oh sure...
}

- (int)getPackage:(char*)name inDirectory:(const char*)where
{
    int count = 0;
    DIR* dirp = opendir(where);

    if (dirp) {
    	struct direct* entry;
	
	while (entry = readdir(dirp)) {
	    if (!strcmp(entry->d_name + entry->d_namlen - 4, ".pkg")) {
	    	if (!count) {
		    strcpy(name, entry->d_name);
		}
		++count;
	    }
	}
	
	closedir(dirp);
    }
    
    return count;
}

- appDidInit:sender
{    
    const char* from;		// Package directory
    const char* to = "";	// Destination directory
    
    [NXApp deactivateSelf];
    
    // First, check the number of arguments that we got, and get them.
    
    if (NXArgc == 1) {
    	static char singleFromDir[MAXPATHLEN + 1];
	const char* myDirectory = [[NXBundle mainBundle] directory];
	char* cptr;
	
    	strcpy(singleFromDir, myDirectory);
	if ((cptr = strchr(singleFromDir + 1, '/')) &&
	    !strchr(cptr + 1, '/')) {
	    
	    int pkgCount;
	    
	    *cptr++ = '\0';
	    
	    // Now we have the name of the disk, look for a package
	    
	    pkgCount = [self getPackage:cptr inDirectory:singleFromDir];
	    
	    if (!pkgCount) {
	    	NXRunLocalizedAlertPanel("Localizable", "No Package",
		    "Unable to find a package to install on the disk %s. Click Quit to terminate the application.",
		    "Quit", NULL, NULL, singleFromDir + 1);
		exit(EXIT_NO_PACKAGE);
	    } else if (pkgCount != 1) {
	    	NXRunLocalizedAlertPanel("Localizable", "Too Many Packages",
		    "There should be only one package on the disk %s. Click Quit to terminate the application.",
		    "Quit", NULL, NULL, singleFromDir + 1);
		exit(EXIT_NO_UNICITY);
	    }
	    
	    cptr[-1] = '/';
	    from = singleFromDir;
	    
	    if (NXRunLocalizedAlertPanel("Localizable",
	    	"Smart Installer",
		"The %s package is about to be installed. While waiting for Installer to be launched, please be patient and insert disks as they are asked for. Now click Install to install the package (or click Quit to terminate).",
		"Install", "Quit", NULL, cptr) != NX_ALERTDEFAULT) {
		exit(EXIT_NO_INSTALL);
	    }
	    
	    // We must fork and re-launch ourselves after having copied the
	    // app in /tmp, otherwise we would not be able to eject a disk
	    // because we are on it...
	    
	    switch (fork()) {
	    	case -1:
		    NXRunLocalizedAlertPanel("Localizable",
			"Smart Installer",
			"Cannot fork a process to do the package installation. Click Quit to terminate.",
			"Quit", NULL, NULL);
		    exit(EXIT_NO_FORK);
		    break;
		
		case 0: {
		    char cmdLine[2048];
		    
		    sprintf(cmdLine, "(cd \"%s\"/..; /bin/tar cf - `/usr/bin/basename \"%s\"`) | (cd /tmp; tar xf -); /tmp/`/usr/bin/basename \"%s\"`/`/usr/bin/basename \"%s\" .app` \"%s\" \"%s\"",
			from, myDirectory, myDirectory, myDirectory, from, to);
		    
		    if (execl("/bin/sh", "sh", "-c", cmdLine, 0) == -1) {
			NXRunLocalizedAlertPanel("Localizable",
			    "Smart Installer",
			    "Cannot run a shell (/bin/sh) to do the installation. Click Quit to terminate.",
			    "Quit", NULL, NULL);
			exit(EXIT_NO_SHELL);
		    }
		    break;
		}
		
		default:
		    exit(EXIT_OK);
	    }
	} else {
	    NXRunLocalizedAlertPanel("Localizable", "Smart Installer",
		"The application is not located where it expects to be (on the root of the disk file system). Please tell your vendor about that...",
		"Quit", NULL, NULL);
	    exit(EXIT_NO_ROOT);
	}
    } else if (NXArgc != 3) {
    	NXRunLocalizedAlertPanel("Localizable", "Smart Installer",
	    "Bad number of arguments (got %d, expected 0 or 2). Please do not launch this application yourself unless it is supplied on the root of the disk file system.",
	    "Quit", NULL, NULL, NXArgc - 1);
	    
	exit(EXIT_USAGE);

#ifdef SMART_CHECK_LOCATION

    } else if ([[installer class] isLocationRoot]) { 
    	    NXRunLocalizedAlertPanel("Localizable", "Smart Installer",
		"The application is not located where it expects to be (on the root of the disk file system). Please tell your vendor about that...",
		"Quit", NULL, NULL);
	    exit(EXIT_NO_ROOT);
	    
#endif

    } else {
	from = NXArgv[1];
	to = NXArgv[2];
    }
    
    [installer setPackage:from andDestination:to];
    
    // Then install the package
    
    [self perform:@selector(installPackageAndExit:) with:self afterDelay:0
    	cancelPrevious:YES];
	
    return self;
}

@end
